import { Page } from 'puppeteer';
import { Recorder } from './Recorder';
import child_process from "child_process";
import * as fs from 'fs';
import * as path from 'path';
import {AudioContext} from 'node-web-audio-api';
import audioBufferToWav from 'audiobuffer-to-wav';
import { delay } from './utils';

const pages: Page[] = [];
const recorderMap = new Map<Page, AudioRecorder>();

// 扩展 Window 接口以支持自定义属性
declare global {
    interface Window {
        save: (str: string, timestamp: number, sessionId: string) => Promise<void>;
        startTime: () => Promise<number>;
        stopRecording: (reason: string) => Promise<void>;
        stopMediaRecorder: () => void;
        log: (message: string) => void;
        mediaRecorder: MediaRecorder | null;
        videoElement: HTMLVideoElement | null;
        mediaSessionId: string;
    }
}

// 音频块接口
interface AudioChunk {
    timestamp: number;
    data: Buffer;
    sessionId: string; // 用于标识不同的录音会话
}

function subscribe(page: Page, ar: AudioRecorder) {
    if (pages.includes(page)) {
        return;
    }
    pages.push(page);
    recorderMap.set(page, ar);
    
    // 暴露保存音频块的函数
    page.exposeFunction("save", function (str: string, timestamp: number, sessionId: string) {
        const recorder = recorderMap.get(page);
        if (recorder) {
            recorder.saveBlob(str, timestamp, sessionId);
        }
    });
    
    // 暴露开始录制的函数
    page.exposeFunction("startTime", async function () {
        const recorder = recorderMap.get(page);
        if (!recorder) return 0;
        
        const t = Date.now() - recorder.duration;
        
        // 确保 audio 目录存在
        const audioDir = path.join(process.cwd(), 'audio');
        if (!fs.existsSync(audioDir)) {
            fs.mkdirSync(audioDir, { recursive: true });
        }
        
        recorder.outputPath = path.join(audioDir, `audio_${t}.wav`);
        recorder.chunkDir = path.join(audioDir, `audio_${t}_chunks`);
        
        // 创建存放音频块的目录
        if (!fs.existsSync(recorder.chunkDir)) {
            fs.mkdirSync(recorder.chunkDir, { recursive: true });
        }
        return recorder.startTime = t;
    });
    
    // 暴露停止录制的函数
    page.exposeFunction("stopRecording", async function () {
        const recorder = recorderMap.get(page);
        if (recorder) {
            recorder.isRecording = false;
        }
    });
    
 
}

export class AudioRecorder extends Recorder {
    private page: Page;
    public isRecording = false;
    public outputPath = "";
    public chunkDir = "";
    private audioChunks: AudioChunk[] = [];
    public startTime = 0;
    public duration = 5000;
    
    // 视频元素监控相关属性
    private videoSrc = "";
    private videoChangeDetectionInterval: NodeJS.Timeout | null = null;
    private readonly VIDEO_DETECTION_INTERVAL = 1000; // 每秒检查一次
    private sessionCounter = 0; // 用于生成唯一的会话ID
    
    // 心跳检测相关属性
    private heartbeatInterval: NodeJS.Timeout | null = null;
    private lastChunkTime = 0;
    private readonly HEARTBEAT_CHECK_INTERVAL = this.duration; // 每5秒检查一次
    private readonly MAX_SILENCE_DURATION = this.duration*3; // 15秒没有音频则触发刷新

    constructor(page: Page) {
        super();
        this.page = page;
        subscribe(page, this);

        // 添加页面刷新事件监听
        this.page.on('load', async () => {
            console.log('页面已刷新，重新注入录音脚本...');
            if (this.isRecording) {
                try {
                    // 生成新的会话ID
                    const newSessionId = `session_${Date.now()}_${++this.sessionCounter}`;
                    await this.injectScript(newSessionId);
                    console.log(`页面刷新后重新注入脚本成功，新会话ID: ${newSessionId}`);
                } catch (err) {
                    console.error('页面刷新后重新注入脚本失败:', err);
                }
            }
        });
    }

    // 开始心跳检测
    private startHeartbeatCheck(): void {
        this.lastChunkTime = Date.now();
        
        this.heartbeatInterval = setInterval(async () => {
            if (!this.isRecording) {
                this.stopHeartbeatCheck();
                return;
            }
            
            const now = Date.now();
            const silenceDuration = now - this.lastChunkTime;
            
            if (silenceDuration > this.MAX_SILENCE_DURATION) {
                console.log(`心跳检测: ${silenceDuration}ms 没有收到音频数据，发送 E 键刷新...`);
                try {
                    if (!this.page.isClosed()) {
                        await this.page.keyboard.press('E');
                        console.log('已发送 E 键刷新');
                    }
                } catch (err) {
                    console.error('发送 E 键时出错:', err);
                }
                // 重置计时器
                this.lastChunkTime = now;
            }
        }, this.HEARTBEAT_CHECK_INTERVAL);
    }

    // 停止心跳检测
    private stopHeartbeatCheck(): void {
        if (this.heartbeatInterval) {
            clearInterval(this.heartbeatInterval);
            this.heartbeatInterval = null;
        }
    }

    // 开始视频变化检测
    private startVideoChangeDetection(): void {
        if (this.videoChangeDetectionInterval) {
            clearInterval(this.videoChangeDetectionInterval);
        }
        
        this.videoChangeDetectionInterval = setInterval(async () => {
            if (!this.isRecording) {
                this.stopVideoChangeDetection();
                return;
            }
            
            try {
                // 检查视频元素的源是否发生变化
                const videoInfo = await this.page.evaluate(() => {
                    const videoEl = document.querySelector('video');
                    if (!videoEl) return { exists: false, src: '' };
                    
                    return {
                        exists: true,
                        src: videoEl.src || '',
                        currentTime: videoEl.currentTime,
                        paused: videoEl.paused
                    };
                });
                
                if (!videoInfo.exists) {
                    console.log('未找到视频元素，继续检测...');
                    return;
                }
                
                const currentSrc = videoInfo.src;
                
                // 检测视频源是否改变
                if (this.videoSrc && this.videoSrc !== currentSrc) {
                    console.log(`检测到视频源变化: ${this.videoSrc} -> ${currentSrc}`);
                    
                    // 生成新的会话ID
                    const newSessionId = `session_${Date.now()}_${++this.sessionCounter}`;
                    
                    // 重新初始化录音器
                    await this.reinitializeRecorder(newSessionId);
                }
                
                // 更新当前视频源
                this.videoSrc = currentSrc;
                
            } catch (err) {
                console.error('视频元素检测时出错:', err);
            }
        }, this.VIDEO_DETECTION_INTERVAL);
    }

    // 停止视频变化检测
    private stopVideoChangeDetection(): void {
        if (this.videoChangeDetectionInterval) {
            clearInterval(this.videoChangeDetectionInterval);
            this.videoChangeDetectionInterval = null;
        }
    }

    // 重新初始化录音器
    private async reinitializeRecorder(sessionId: string): Promise<void> {
        console.log(`重新初始化录音器，会话ID: ${sessionId}`);
        
        try {
            // 停止当前的 MediaRecorder
            await this.page.evaluate(async () => {
                try {
                    if (window.mediaRecorder && window.mediaRecorder.state !== 'inactive') {
                        window.log('停止当前MediaRecorder');
                        
                        // 移除事件处理程序以防止触发不必要的操作
                        window.mediaRecorder.ondataavailable = null;
                        window.mediaRecorder.onstop = null;
                        window.mediaRecorder.onerror = null;
                        
                        // 停止录制
                        window.mediaRecorder.stop();
                    }
                    
                    window.mediaRecorder = null;
                    return true;
                } catch (err) {
                    window.log(`停止MediaRecorder时出错: ${err}`);
                    return false;
                }
            });
            
            // 注入新的录音脚本
            await this.injectScript(sessionId);
            
            console.log('已重新初始化录音器');
        } catch (err) {
            console.error('重新初始化录音器时出错:', err);
        }
    }

    // 保存音频块
    saveBlob(buffer: string, timestamp: number, sessionId: string): void {
        if (!this.isRecording) {
            console.warn('录音已停止，忽略音频块');
            return;
        }
        
        // 更新最后收到音频块的时间
        this.lastChunkTime = Date.now();
        
        const base64Index = buffer.indexOf(";base64,");
        const base64String = base64Index >= 0 ? buffer.substring(base64Index + 8) : null;
        
        if (base64String) {
            const audioBuffer = Buffer.from(base64String, "base64");            
            
            // 记录时间戳、缓冲区和会话ID
            this.audioChunks.push({
                timestamp: timestamp,
                data: audioBuffer,
                sessionId: sessionId
            });
            
            console.log(`保存音频块: 时间戳 ${timestamp}, 大小: ${audioBuffer.length} 字节, 会话ID: ${sessionId}`);
        } else {
            console.warn('收到无效的base64字符串');
        }
    }

    // 注入录音脚本
    private async injectScript(sessionId: string = `session_${Date.now()}_${this.sessionCounter++}`): Promise<void> {
        await this.page.evaluate(async (config) => {
            // 绑定视频元素事件
            function bindVideoEvents(videoElement: HTMLVideoElement) {
                videoElement.onplay = () => {
                    window.log('视频已播放');
                };
                
                videoElement.onended = () => {
                    window.log('视频已结束');
                };
                
                videoElement.onerror = () => {
                    window.log(`视频错误: ${videoElement.error?.message}`);
                };
            }
            
            // 保存当前会话ID
            window.mediaSessionId = config.sessionId;
            window.log(`使用会话ID: ${window.mediaSessionId}`);
            
            // 确保不重复录制
            if (window.mediaRecorder && window.mediaRecorder.state === 'recording') {
                window.log(`已有正在录制的MediaRecorder (${window.mediaSessionId})，先停止它`);
                
                try {
                    const oldRecorder = window.mediaRecorder;
                    // 移除事件处理程序以防止触发不必要的操作
                    oldRecorder.ondataavailable = null;
                    oldRecorder.onstop = null;
                    oldRecorder.onerror = null;
                    oldRecorder.stop();
                } catch (err) {
                    window.log(`停止旧MediaRecorder出错: ${err}`);
                }
                
                window.mediaRecorder = null;
            }
            
            async function captureAndSendAudio() {
                let isRecording = false;
                
                window.log('开始音频捕获');
                
                // 查找视频元素
                const videoElement = document.querySelector('video') as HTMLVideoElement;
                if (!videoElement) {
                    window.log('未找到视频元素，将在1秒后重试...');
                    setTimeout(captureAndSendAudio, 1000);
                    return;
                }
                
                window.log(`找到视频元素，src: ${videoElement.src || '未设置'}`);
                window.videoElement = videoElement;
                
                // 绑定视频元素事件
                bindVideoEvents(videoElement);
                
                // 尝试获取视频流
                let stream: MediaStream | null = null;
                try {
                    // @ts-ignore
                    stream = videoElement.captureStream?.() || videoElement.mozCaptureStream?.() || videoElement.webkitCaptureStream?.();
                } catch (err) {
                    window.log(`使用标准方法捕获流时出错: ${err}`);
                    setTimeout(captureAndSendAudio, 1000);
                    return;
                }
                
                if (!stream) {
                    window.log('无法从视频元素捕获流，将在1秒后重试...');
                    setTimeout(captureAndSendAudio, 1000);
                    return;
                }
                
                // 获取音频轨道
                const audioTracks = stream.getAudioTracks();
                window.log(`获得 ${audioTracks.length} 个音频轨道`);
                
                if (audioTracks.length === 0) {
                    window.log('未找到音频轨道，将在1秒后重试...');
                    setTimeout(captureAndSendAudio, 1000);
                    return;
                }
                
                // 创建新的MediaStream只包含音频
                const audioStream = new MediaStream();
                audioTracks.forEach(track => {
                    audioStream.addTrack(track);
                    window.log(`添加音频轨道: ${track.label || '未命名'}`);
                    
                    // 监控音频轨道状态
                    track.onended = () => {
                        window.log(`音频轨道结束: ${track.label || '未命名'}`);
                    };
                    
                    track.onmute = () => {
                        window.log(`音频轨道静音: ${track.label || '未命名'}`);
                    };
                    
                    track.onunmute = () => {
                        window.log(`音频轨道取消静音: ${track.label || '未命名'}`);
                    };
                });
                
                // 使用更可靠的设置创建MediaRecorder
                const options = {
                    mimeType: 'audio/webm;codecs=opus',
                    audioBitsPerSecond: 128000
                };
                
                let mediaRecorder: MediaRecorder;
                try {
                    mediaRecorder = new MediaRecorder(audioStream, options);
                    window.log(`使用mimeType创建MediaRecorder: ${options.mimeType}`);
                } catch (err) {
                    window.log(`无法使用指定选项创建MediaRecorder: ${err}`);
                    try {
                        // 回退到基本选项
                        mediaRecorder = new MediaRecorder(audioStream);
                        window.log(`使用默认选项创建MediaRecorder，mimeType: ${mediaRecorder.mimeType}`);
                    } catch (fallbackErr) {
                        window.log(`无法创建MediaRecorder: ${fallbackErr}`);
                        setTimeout(captureAndSendAudio, 1000);
                        return;
                    }
                }
                
                // 保存全局引用
                window.mediaRecorder = mediaRecorder;
                isRecording = true;
                
                let processingPromise: Promise<void> | null = null;
                let first = true;
                let lastLogTime = Date.now();
                let chunkCount = 0;
                
                mediaRecorder.ondataavailable = async (event) => {
                    if (!isRecording || !window.mediaRecorder) {
                        window.log('录制已停止，忽略数据');
                        return;
                    }
                    
                    if (event.data.size === 0) {
                        window.log('收到空数据块，忽略');
                        return;
                    }
                    
                    chunkCount++;
                    
                    if (first) {
                        await window.startTime();
                        first = false;
                        window.log('录制开始，收到第一个音频块');
                    }
                    
                    const currentTime = Date.now();
                    if (currentTime - lastLogTime > 2000) {
                        window.log(`继续录制中，已收到 ${chunkCount} 个音频块`);
                        lastLogTime = currentTime;
                    }
                    
                    // 等待任何之前的处理完成
                    if (processingPromise) {
                        try {
                            await processingPromise;
                        } catch (err) {
                            window.log(`之前的处理出错: ${err}`);
                        }
                    }
                    
                    const base64 = await new Promise<string>((resolve) => {
                        const reader = new FileReader();
                        reader.onloadend = () => {
                            resolve(reader.result as string);
                        };
                        reader.onerror = () => {
                            window.log(`读取块数据出错: ${reader.error}`);
                            resolve('');
                        };
                        reader.readAsDataURL(event.data);
                    });
                    
                    if (!base64) {
                        window.log('无法将块转换为base64');
                        return;
                    }
                    
                    try {
                        processingPromise = window.save(base64, currentTime, window.mediaSessionId);
                        await processingPromise;
                    } catch (err) {
                        window.log(`保存音频块出错: ${err}`);
                    }
                };
                
                window.stopMediaRecorder = function() {
                    if (!isRecording) return;
                    
                    isRecording = false;
                    
                    if (mediaRecorder && mediaRecorder.state !== 'inactive') {
                        window.log('停止媒体录制器');
                        mediaRecorder.stop();
                    }
                    
                    window.stopRecording("");
                };
                
                mediaRecorder.onstop = () => {
                    window.log('MediaRecorder已停止');
                    isRecording = false;
                };
                
                mediaRecorder.onerror = (event) => {
                    window.log(`MediaRecorder错误: ${event.error}`);
                };
                
                try {
                    mediaRecorder.start(config.duration);
                    window.log(`MediaRecorder已启动，块持续时间: ${config.duration}ms`);
                } catch (err) {
                    window.log(`无法启动MediaRecorder: ${err}`);
                    isRecording = false;
                }
            }
            
            // 开始音频捕获
            captureAndSendAudio();
        }, {
            duration: this.duration,
            sessionId: sessionId
        });
    }

    // 开始录音
    async start(): Promise<void> {
        console.log("开始音频录制...");
        this.audioChunks.length = 0;
        this.startTime = 0; 
        this.videoSrc = "";
        this.sessionCounter = 0;
        
        try {
            this.isRecording = true;
            // 生成初始会话ID
            const initialSessionId = `session_${Date.now()}_${this.sessionCounter++}`;
            await this.injectScript(initialSessionId);
            console.log(`音频录制脚本注入成功，初始会话ID: ${initialSessionId}`);
            
            // 添加心跳检测
            this.startHeartbeatCheck();
            
            // 添加视频变化检测
            this.startVideoChangeDetection();
        } catch (err) {
            this.isRecording = false;
            console.error("启动音频录制失败:", err);
            throw err;
        }
    }

    // 停止录音并处理结果
    async stop(): Promise<string> {
        console.log("停止音频录制...");
        
        if (!this.isRecording) {
            console.warn('音频录制未激活');
            return "";
        }
        
        this.isRecording = false;
        
        // 停止心跳检测
        this.stopHeartbeatCheck();
        
        // 停止视频变化检测
        this.stopVideoChangeDetection();
        
        try {
            if (!this.page.isClosed()) {
                console.log("在页面中停止媒体录制器...");
                await this.page.evaluate(() => {
                    if (window.stopMediaRecorder) {
                        window.stopMediaRecorder();
                    }
                });
            }
        } catch (e) {
            console.error("停止媒体录制器时出错:", e);
        }
      
        console.log(`已录制 ${this.audioChunks.length} 个音频块`);
        if (this.audioChunks.length === 0) {
            console.error("未录制任何音频块");
            return "";
        }
    
        // 按时间戳排序
        this.audioChunks.sort((a, b) => a.timestamp - b.timestamp);
        
        // 设置输出路径
        if (!this.outputPath || this.outputPath.trim() === '') {
            const timestamp = Date.now();
            // 确保 audio 目录存在
            const audioDir = path.join(process.cwd(), 'audio');
            if (!fs.existsSync(audioDir)) {
                fs.mkdirSync(audioDir, { recursive: true });
            }
            this.outputPath = path.join(audioDir, `audio_${timestamp}.wav`);
        } else {
            // 确保扩展名为WAV
            this.outputPath = this.outputPath.replace(/\.\w+$/, '.wav');
        }
    
        console.log(`输出路径: ${this.outputPath}`);
        
        try {
            // 创建临时目录
            const audioDir = path.join(process.cwd(), 'audio');
            if (!fs.existsSync(audioDir)) {
                fs.mkdirSync(audioDir, { recursive: true });
            }
            const tempDir = path.join(audioDir, `temp_${Date.now()}`);
            fs.mkdirSync(tempDir, { recursive: true });
            
            const tempFile = path.join(tempDir, 'temp.webm');
            
            // 合并所有块并保存
            const combinedBuffer = Buffer.concat(this.audioChunks.map(chunk => chunk.data));
            fs.writeFileSync(tempFile, combinedBuffer);
            
            // 使用FFmpeg将WebM转换为44.1kHz, 16位的PCM WAV
            const tempWavFile = path.join(tempDir, 'temp.wav');
            await new Promise<void>((resolve, reject) => {
                const ffmpeg = child_process.spawn('ffmpeg', [
                    '-i', tempFile,
                    '-acodec', 'pcm_s16le',
                    '-ar', '44100',
                    '-ac', '2',
                    '-y',
                    tempWavFile
                ]);
                
                ffmpeg.on('close', (code) => {
                    if (code === 0) resolve();
                    else reject(new Error(`转换WAV失败，错误码: ${code}`));
                });
            });
            
            // 读取音频数据到AudioContext
            const audioContext = new AudioContext();
            const fileBuffer = fs.readFileSync(tempWavFile);
            const audioBuffer = await audioContext.decodeAudioData(fileBuffer.buffer as ArrayBuffer);
            
            // 分析时间线上的缝隙
            const startTimestamp = this.audioChunks[0].timestamp;
            const gaps = [];
            
            for (let i = 1; i < this.audioChunks.length; i++) {
                const prevChunk = this.audioChunks[i-1];
                const currentChunk = this.audioChunks[i];
                
                const expectedTimestamp = prevChunk.timestamp + this.duration;
                const timeDiff = currentChunk.timestamp - expectedTimestamp;
                
                if (timeDiff > 100) {  // 如果间隔超过100ms则认为有缝隙
                    console.log(`在 ${expectedTimestamp}ms 处检测到 ${timeDiff}ms 的缝隙`);
                    gaps.push({
                        startTime: expectedTimestamp - startTimestamp,
                        endTime: currentChunk.timestamp - startTimestamp,
                        duration: timeDiff
                    });
                }
            }
            
            console.log(`总共检测到 ${gaps.length} 个时间缝隙`);
            
            // 如果没有缝隙，直接输出WAV
            if (gaps.length === 0) {
                fs.copyFileSync(tempWavFile, this.outputPath);
                console.log(`成功创建输出文件: ${this.outputPath}`);
                
                // 清理临时文件
                fs.rmSync(tempDir, { recursive: true, force: true });
                return this.outputPath;
            }
            
            // 处理有缝隙的情况 - 使用Web Audio API
            // 创建一个新的AudioBuffer，长度为原始长度加上所有缝隙的长度
            const totalGapDuration = gaps.reduce((total, gap) => total + gap.duration, 0);
            const newDuration = audioBuffer.duration + totalGapDuration / 1000; // 转为秒
            
            const newAudioBuffer = audioContext.createBuffer(
                audioBuffer.numberOfChannels,
                Math.ceil(newDuration * audioBuffer.sampleRate),
                audioBuffer.sampleRate
            );
            
            // 复制原始数据并在缝隙处插入静音
            for (let channel = 0; channel < audioBuffer.numberOfChannels; channel++) {
                const channelData = audioBuffer.getChannelData(channel);
                const newChannelData = newAudioBuffer.getChannelData(channel);
                
                let currentInputPosition = 0;
                let currentOutputPosition = 0;
                
                // 处理每个缝隙前的数据
                for (const gap of gaps) {
                    // 计算当前缝隙前的采样点数
                    const gapStartSample = Math.floor((gap.startTime / 1000) * audioBuffer.sampleRate);
                    
                    // 复制缝隙前的音频数据
                    for (let i = currentInputPosition; i < gapStartSample && i < channelData.length; i++) {
                        newChannelData[currentOutputPosition++] = channelData[i];
                    }
                    
                    // 更新输入位置
                    currentInputPosition = gapStartSample;
                    
                    // 插入静音（全是0）
                    const silenceSamples = Math.floor((gap.duration / 1000) * audioBuffer.sampleRate);
                    currentOutputPosition += silenceSamples; // 静音部分全是0，无需赋值
                    
                    // 更新输入位置到缝隙后
                    const gapEndSample = Math.floor((gap.endTime / 1000) * audioBuffer.sampleRate);
                    currentInputPosition = gapEndSample;
                }
                
                // 复制剩余数据
                for (let i = currentInputPosition; i < channelData.length; i++) {
                    if (currentOutputPosition < newChannelData.length) {
                        newChannelData[currentOutputPosition++] = channelData[i];
                    }
                }
            }
            
            // 将AudioBuffer转换为WAV并保存
            const wavBuffer = audioBufferToWav(newAudioBuffer);
            fs.writeFileSync(this.outputPath, Buffer.from(wavBuffer));
            
            console.log(`成功创建带有缝隙修复的输出文件: ${this.outputPath}`);
            
            // 清理临时文件
            fs.rmSync(tempDir, { recursive: true, force: true });
            
            return this.outputPath;
            
        } catch (error) {
            console.error('处理音频时出错:', error);
            
            // 故障恢复：直接使用FFmpeg合并并转换为WAV
            try {
                console.log('尝试使用备用方法处理音频...');
                
                // 确保 audio 目录存在
                const audioDir = path.join(process.cwd(), 'audio');
                if (!fs.existsSync(audioDir)) {
                    fs.mkdirSync(audioDir, { recursive: true });
                }
                
                const rawConcatFile = path.join(audioDir, `raw_concat_${Date.now()}.webm`);
                const combinedBuffer = Buffer.concat(this.audioChunks.map(chunk => chunk.data));
                fs.writeFileSync(rawConcatFile, combinedBuffer);
                
                await new Promise<void>((resolve, reject) => {
                    const ffmpeg = child_process.spawn('ffmpeg', [
                        '-i', rawConcatFile,
                        '-acodec', 'pcm_s16le',
                        '-ar', '44100',
                        '-ac', '2',
                        '-y',
                        this.outputPath
                    ]);
                    
                    ffmpeg.on('close', (code) => {
                        if (code === 0) {
                            resolve();
                        } else {
                            reject(new Error(`FFmpeg转换失败，错误码: ${code}`));
                        }
                    });
                });
                
                // 清理临时文件
                fs.unlinkSync(rawConcatFile);
                
                console.log(`备用处理: 创建了WAV文件 ${this.outputPath}`);
            } catch (err) {
                console.error('备用处理也失败:', err);
            }
            
            return this.outputPath;
        }
    }
}